export default class Rain {
  constructor(basicCesium, option) {
    this.basicCesium = basicCesium
    this.viewer = basicCesium.viewer
    this.scene = basicCesium.viewer.scene

    this.option = option || {};
    this.collection = basicCesium.viewer.scene.postProcessStages;

    this.initRain()
    this.initSnow()
  }

  initRain() {
    this.scene.skyAtmosphere.hueShift = -0.8;
    this.scene.skyAtmosphere.saturationShift = -0.7;
    this.scene.skyAtmosphere.brightnessShift = -0.33;
    this.scene.fog.density = 0.001;
    this.scene.fog.minimumBrightness = 0.8;
    this.rain = new Cesium.PostProcessStage({
      name: '冷冷的冰雨',
      fragmentShader: this.rainShader(),
      uniforms: {
        tiltAngle: Cesium.defaultValue(this.option.tiltAngle, -0.3),
        rainSize: Cesium.defaultValue(this.option.rainSize, 0.3),
        rainSpeed: Cesium.defaultValue(this.option.rainSpeed, 160.0),
      }
    });
    this.collection.add(this.rain);
  }
  rainShader() {
    return `uniform sampler2D colorTexture;
            varying vec2 v_textureCoordinates;
            uniform float tiltAngle;
            uniform float rainSize;
            uniform float rainSpeed;
            float hash(float x) {
                return fract(sin(x * 133.3) * 13.13);
            }
            void main(void) {
                float time = czm_frameNumber / rainSpeed;
                vec2 resolution = czm_viewport.zw;
                vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);
                vec3 c = vec3(.6, .7, .8);
                float a = tiltAngle;
                float si = sin(a), co = cos(a);
                uv *= mat2(co, -si, si, co);
                uv *= length(uv + vec2(0, 4.9)) * rainSize + 1.;
                float v = 1. - sin(hash(floor(uv.x * 100.)) * 2.);
                float b = clamp(abs(sin(20. * time * v + uv.y * (5. / (2. + v)))) - .95, 0., 1.) * 20.;
                c *= v * b;
                gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c, 1), .5);
            }`;
  }

  initSnow() {
    this.snow = new Cesium.PostProcessStage({
      name: '2002年的第一场雪',
      fragmentShader: this.snowShader(),
      uniforms: {
        snowSize: Cesium.defaultValue(this.option.snowSize, 0.02), //最好小于0.02,
        snowSpeed: Cesium.defaultValue(this.option.snowSpeed, 160.0)
      }
    });
    this.collection.add(this.snow);
  }

  snowShader() {
    return `uniform sampler2D colorTexture;
            varying vec2 v_textureCoordinates;
            uniform float snowSpeed;
            uniform float snowSize;
            float snow(vec2 uv, float scale)  {
              float time = czm_frameNumber / snowSpeed;
              float w = smoothstep(1., 0., -uv.y * (scale / 10.));
              if (w < .1) return 0.;
              uv += time / scale;
              uv.y += time * 2. / scale;
              uv.x += sin(uv.y + time * .5) / scale;
              uv *= scale;
              vec2 s = floor(uv), f = fract(uv), p;
              float k = 3., d;
              p = .5 + .35 * sin(11. * fract(sin((s + p + scale) * mat2(7, 3, 6, 5)) * 5.)) - f;
              d = length(p);
              k = min(d, k);
              k = smoothstep(0., k, sin(f.x + f.y) * snowSize);
              return k * w;
            }
            void main(void) {
              vec2 resolution = czm_viewport.zw;
              vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);
              vec3 finalColor = vec3(0);
              //float c=smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));
              float c = 0.;
              c += snow(uv, 30.) * .0;
              c += snow(uv, 20.) * .0;
              c += snow(uv, 15.) * .0;
              c += snow(uv, 10.);
              c += snow(uv, 8.);
              c += snow(uv, 6.);
              c += snow(uv, 5.);
              finalColor = (vec3(c));
              gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(finalColor, 1), .5);
            }`;

  }

  remove() {
    if (this.rain) this.collection.remove(this.rain);
    if (this.snow) this.collection.remove(this.snow);
    this.rain = undefined;
    this.snow = undefined;
  }
}